#include "file_utils.h"
#include "my_db.h"
#include <algorithm>
#include <cctype>
#include <stdexcept>

/*
数据结构形如：
DB{
name:xxx
table{
name:xxxx
column{
name:xxx
type:xxx
value{
xxx
xxx
xxxx
xxxxx
xxxxxxx
....
}
}
}
table{
name:xxxx
}
.....
}
*/

/**
 * 将数据库结构和数据写入文件
 *
 * @param db_file 数据库文件路径，指定文件将被写入数据库信息
 */
void write_file(string db_file)
{
    string tmp;
    /*临时存储，内存中构建完整数据库*/
    for (const auto &db : database)
    {
        /*使用const引用，避免拷贝性能损耗且更安全*/
        tmp += "DB{\n";
        tmp += "name:" + db.name + "\n";
        for (const auto &table : db.tables)
        {
            tmp += "table{\n";
            tmp += "name:" + table.name + "\n";
            for (const auto &column : table.columns)
            {
                tmp += "column{\n";
                tmp += "name:" + column.name + "\n";
                tmp += "type:" + column.type + "\n";
                tmp += "value{\n";
                for (const auto &val : column.values)
                {
                    tmp = tmp + to_string(val) + "\n";
                    /*to_string定义在my_db.cpp中*/
                }
                tmp += "}\n"; // value
                tmp += "}\n"; // column
            }
            tmp += "}\n";
        }
        tmp += "}\n";
    }
    /*C++文件写入*/
    std::ofstream out(db_file);
    out << tmp;
    out.close();
}

/*去除前后空格*/
static inline void ltrim(string &s)
{
    s.erase(s.begin(), std::find_if(s.begin(), s.end(),
                                    [](unsigned char c)
                                    { return !std::isspace(c); }));
}
static inline void rtrim(string &s)
{
    s.erase(std::find_if(s.rbegin(), s.rend(),
                         [](unsigned char c)
                         { return !std::isspace(c); })
                .base(),
            s.end());
}
static inline void trim(string &s)
{
    ltrim(s);
    rtrim(s);
}
/* 把一行字符串变成 variant，依据字段自身保存的 type 决定 */
static ValueType str2var(const string &s, const string &type)
{
    if (type == "int")
        return std::stoi(s);
    if (type == "float")
        return std::stof(s);
    if (type == "double")
        return std::stod(s);
    return s; // 其它一律当作 string
}

void read_file(string db_file)
{
    database.clear(); // 先把全局库清空
    std::ifstream in(db_file);
    if (!in)
    {
        database.clear();
        write_file(db_file);
        warn("open %s failed,try to make a new one",db_file.c_str());
        in.open(db_file);
        if(!in.is_open()){
        error("无法打开数据库文件");
        return;
        }
    }
   
    /*状态机*/
    enum class State
    {
        Idle,
        InDB,
        InTable,
        InColumn,
        InValue
    };
    State state = State::Idle;
    db curDB;
    table curTable;
    column curCol;
    string rawLine;
    while (std::getline(in, rawLine))
    {
        trim(rawLine);
        if (rawLine.empty())
            continue; // 忽略空行
        /*********************  进入 / 退出层级  ************************/
        if (rawLine == "DB{")
        {
            state = State::InDB;
            curDB = {};
            continue;
        }
        if (rawLine == "table{")
        {
            state = State::InTable;
            curTable = {};
            continue;
        }
        if (rawLine == "column{")
        {
            state = State::InColumn;
            curCol = {};
            continue;
        }
        if (rawLine == "value{")
        {
            state = State::InValue;
            continue;
        }
        /******** 离开当前层级 *********/
        if (rawLine == "}") 
        {
            
            switch (state)
            {
            case State::InValue:         // value } 结束
                state = State::InColumn; // 回到 column 层
                break;
            case State::InColumn: // column } 结束
                curTable.columns.emplace_back(std::move(curCol));
                state = State::InTable;
                break;
            case State::InTable: // table } 结束
                curDB.tables.emplace_back(std::move(curTable));
                state = State::InDB;
                break;
            case State::InDB: // DB } 结束
                database.emplace_back(std::move(curDB));
                state = State::Idle;
                break;
            default:
                break;
            }
            continue;
        }
        /*********************  普通字段  ************************/
        if (rawLine.rfind("name:", 0) == 0) // 以 "name:" 开头
        {
            string name = rawLine.substr(5); // 去掉前缀"name:""
            switch (state)
            {
            case State::InDB:
                curDB.name = name;
                break;
            case State::InTable:
                curTable.name = name;
                break;
            case State::InColumn:
                curCol.name = name;
                break;
            default:
                break;
            }
            continue;
        }
        if (rawLine.rfind("type:", 0) == 0) // 仅 column 内会出现
        {
            curCol.type = rawLine.substr(5);
            continue;
        }
        /*********************  字段值行  ************************/
        if (state == State::InValue) // 只有在 value{} 内才算数据
        {
            curCol.values.emplace_back(str2var(rawLine, curCol.type));
        }
        /* 其它情况视为格式错误，可自行 throw */
        else error("format error");
    }
    /* 文件结束后自动离开最外层即可 */
}
